home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / TEMPLDEF.PAK / ARRAY.CTT < prev    next >
Text File  |  1997-05-06  |  16KB  |  608 lines

  1. ////////////////////////////////////////////////////////////////////////////
  2. // class CArray<TYPE, ARG_TYPE> - an array containing 'TYPE' elements,
  3. // passed in parameters as ARG_TYPE
  4. //
  5. // optional definitions:
  6. //  IS_SERIAL       - include serialization (see below for types)
  7. //  IS_RAW_SERIAL   - use CArchive::Write and Read for serialization
  8. //  IS_ARCHIVE_SERIAL - use CArchive insersion, extraction for serialization
  9. //  HAS_CREATE      - call constructors and destructors
  10. //
  11. // This is a part of the Microsoft Foundation Classes C++ library.
  12. // Copyright (C) 1992 Microsoft Corporation
  13. // All rights reserved.
  14. //
  15. // This source code is only intended as a supplement to the
  16. // Microsoft Foundation Classes Reference and related
  17. // electronic documentation provided with the library.
  18. // See these sources for detailed information regarding the
  19. // Microsoft Foundation Classes product.
  20. ////////////////////////////////////////////////////////////////////////////
  21.  
  22. //$DECLARE_TEMPLATE
  23. ////////////////////////////////////////////////////////////////////////////
  24. template<class TYPE, class ARG_TYPE>
  25. class CArray : public CObject
  26. {
  27. $ifdef IS_SERIAL
  28.     DECLARE_SERIAL(CArray)
  29. $else
  30.     DECLARE_DYNAMIC(CArray)
  31. $endif  //!IS_SERIAL
  32. public:
  33.  
  34. // Construction
  35.     CArray();
  36.  
  37. // Attributes
  38.     int GetSize() const;
  39.     int GetUpperBound() const;
  40.     void SetSize(int nNewSize, int nGrowBy = -1);
  41.  
  42. // Operations
  43.     // Clean up
  44.     void FreeExtra();
  45.     void RemoveAll();
  46.  
  47.     // Accessing elements
  48.     TYPE GetAt(int nIndex) const;
  49.     void SetAt(int nIndex, ARG_TYPE newElement);
  50.     TYPE& ElementAt(int nIndex);
  51.  
  52.     // Direct Access to the element data (may return NULL)
  53.     const TYPE* GetData() const;
  54.     TYPE* GetData();
  55.  
  56.     // Potentially growing the array
  57.     void SetAtGrow(int nIndex, ARG_TYPE newElement);
  58.     int Add(ARG_TYPE newElement);
  59.     int Append(const CArray& src);
  60.     void Copy(const CArray& src);
  61.  
  62.     // overloaded operator helpers
  63.     TYPE operator[](int nIndex) const;
  64.     TYPE& operator[](int nIndex);
  65.  
  66.     // Operations that move elements around
  67.     void InsertAt(int nIndex, ARG_TYPE newElement, int nCount = 1);
  68.     void RemoveAt(int nIndex, int nCount = 1);
  69.     void InsertAt(int nStartIndex, CArray* pNewArray);
  70.  
  71. // Implementation
  72. protected:
  73.     TYPE* m_pData;   // the actual array of data
  74.     int m_nSize;     // # of elements (upperBound - 1)
  75.     int m_nMaxSize;  // max allocated
  76.     int m_nGrowBy;   // grow amount
  77.  
  78. public:
  79.     ~CArray();
  80. $ifdef IS_SERIAL
  81.     void Serialize(CArchive&);
  82. $endif  //IS_SERIAL
  83. #ifdef _DEBUG
  84.     void Dump(CDumpContext&) const;
  85.     void AssertValid() const;
  86. #endif
  87.  
  88. protected:
  89.     // local typedefs for class templates
  90.     typedef TYPE BASE_TYPE;
  91.     typedef ARG_TYPE BASE_ARG_TYPE;
  92. };
  93.  
  94. //$IMPLEMENT_TEMPLATE_INLINES
  95. ////////////////////////////////////////////////////////////////////////////
  96.  
  97. template<class TYPE, class ARG_TYPE>
  98. _AFXCOLL_INLINE int CArray<TYPE, ARG_TYPE>::GetSize() const
  99.     { return m_nSize; }
  100. template<class TYPE, class ARG_TYPE>
  101. _AFXCOLL_INLINE int CArray<TYPE, ARG_TYPE>::GetUpperBound() const
  102.     { return m_nSize-1; }
  103. template<class TYPE, class ARG_TYPE>
  104. _AFXCOLL_INLINE void CArray<TYPE, ARG_TYPE>::RemoveAll()
  105.     { SetSize(0); }
  106. template<class TYPE, class ARG_TYPE>
  107. _AFXCOLL_INLINE TYPE CArray<TYPE, ARG_TYPE>::GetAt(int nIndex) const
  108.     { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  109.         return m_pData[nIndex]; }
  110. template<class TYPE, class ARG_TYPE>
  111. _AFXCOLL_INLINE void CArray<TYPE, ARG_TYPE>::SetAt(int nIndex, ARG_TYPE newElement)
  112.     { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  113.         m_pData[nIndex] = newElement; }
  114. template<class TYPE, class ARG_TYPE>
  115. _AFXCOLL_INLINE TYPE& CArray<TYPE, ARG_TYPE>::ElementAt(int nIndex)
  116.     { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  117.         return m_pData[nIndex]; }
  118. template<class TYPE, class ARG_TYPE>
  119. _AFXCOLL_INLINE const TYPE* CArray<TYPE, ARG_TYPE>::GetData() const
  120.     { return (const TYPE*)m_pData; }
  121. template<class TYPE, class ARG_TYPE>
  122. _AFXCOLL_INLINE TYPE* CArray<TYPE, ARG_TYPE>::GetData()
  123.     { return (TYPE*)m_pData; }
  124. template<class TYPE, class ARG_TYPE>
  125. _AFXCOLL_INLINE int CArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
  126.     { int nIndex = m_nSize;
  127.         SetAtGrow(nIndex, newElement);
  128.         return nIndex; }
  129. template<class TYPE, class ARG_TYPE>
  130. _AFXCOLL_INLINE TYPE CArray<TYPE, ARG_TYPE>::operator[](int nIndex) const
  131.     { return GetAt(nIndex); }
  132. template<class TYPE, class ARG_TYPE>
  133. _AFXCOLL_INLINE TYPE& CArray<TYPE, ARG_TYPE>::operator[](int nIndex)
  134.     { return ElementAt(nIndex); }
  135.  
  136. //$IMPLEMENT_TEMPLATE
  137. // This is a part of the Microsoft Foundation Classes C++ library.
  138. // Copyright (C) 1992-1995 Microsoft Corporation
  139. // All rights reserved.
  140. //
  141. // This source code is only intended as a supplement to the
  142. // Microsoft Foundation Classes Reference and related
  143. // electronic documentation provided with the library.
  144. // See these sources for detailed information regarding the
  145. // Microsoft Foundation Classes product.
  146.  
  147. /////////////////////////////////////////////////////////////////////////////
  148. //
  149. // Implementation of parameterized Array
  150. //
  151. /////////////////////////////////////////////////////////////////////////////
  152. // NOTE: we allocate an array of 'm_nMaxSize' elements, but only
  153. //  the current size 'm_nSize' contains properly constructed
  154. //  objects.
  155.  
  156. #include "stdafx.h"
  157.  
  158. #ifdef AFX_COLL_SEG
  159. #pragma code_seg(AFX_COLL_SEG)
  160. #endif
  161.  
  162. #ifdef _DEBUG
  163. #undef THIS_FILE
  164. static char THIS_FILE[] = __FILE__;
  165. #endif
  166.  
  167. #define new DEBUG_NEW
  168.  
  169. $ifdef HAS_CREATE
  170. /////////////////////////////////////////////////////////////////////////////
  171.  
  172. #include "elements.h"  // used for special creation
  173.  
  174. static void ConstructElements(TYPE* pNewData, int nCount)
  175. {
  176.     ASSERT(nCount >= 0);
  177.  
  178.     while (nCount--)
  179.     {
  180.         ConstructElement(pNewData);
  181.         pNewData++;
  182.     }
  183. }
  184.  
  185. static void DestructElements(TYPE* pOldData, int nCount)
  186. {
  187.     ASSERT(nCount >= 0);
  188.  
  189.     while (nCount--)
  190.     {
  191.         DestructElement(pOldData);
  192.         pOldData++;
  193.     }
  194. }
  195.  
  196. static void CopyElements(TYPE* pDest, TYPE* pSrc, int nCount)
  197. {
  198.     ASSERT(nCount >= 0);
  199.  
  200.     while (nCount--)
  201.     {
  202.         *pDest = *pSrc;
  203.         ++pDest;
  204.         ++pSrc;
  205.     }
  206. }
  207. $endif //HAS_CREATE
  208.  
  209. /////////////////////////////////////////////////////////////////////////////
  210.  
  211. template<class TYPE, class ARG_TYPE>
  212. CArray<TYPE, ARG_TYPE>::CArray()
  213. {
  214.     m_pData = NULL;
  215.     m_nSize = m_nMaxSize = m_nGrowBy = 0;
  216. }
  217.  
  218. template<class TYPE, ARG_TYPE>
  219. CArray<TYPE, ARG_TYPE>::~CArray()
  220. {
  221.     ASSERT_VALID(this);
  222.  
  223. $ifdef HAS_CREATE
  224.     DestructElements(m_pData, m_nSize);
  225. $endif //HAS_CREATE
  226.     delete[] (BYTE*)m_pData;
  227. }
  228.  
  229. template<class TYPE, class ARG_TYPE>
  230. void CArray<TYPE, ARG_TYPE>::SetSize(int nNewSize, int nGrowBy)
  231. {
  232.     ASSERT_VALID(this);
  233.     ASSERT(nNewSize >= 0);
  234.  
  235.     if (nGrowBy != -1)
  236.         m_nGrowBy = nGrowBy;  // set new size
  237.  
  238.     if (nNewSize == 0)
  239.     {
  240.         // shrink to nothing
  241. $ifdef HAS_CREATE
  242.         DestructElements(m_pData, m_nSize);
  243. $endif //HAS_CREATE
  244.         delete[] (BYTE*)m_pData;
  245.         m_pData = NULL;
  246.         m_nSize = m_nMaxSize = 0;
  247.     }
  248.     else if (m_pData == NULL)
  249.     {
  250.         // create one with exact size
  251. #ifdef SIZE_T_MAX
  252.         ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE));    // no overflow
  253. #endif
  254.         m_pData = (TYPE*) new BYTE[nNewSize * sizeof(TYPE)];
  255. $ifdef HAS_CREATE
  256.         ConstructElements(m_pData, nNewSize);
  257. $else
  258.         memset(m_pData, 0, nNewSize * sizeof(TYPE));  // zero fill
  259. $endif
  260.         m_nSize = m_nMaxSize = nNewSize;
  261.     }
  262.     else if (nNewSize <= m_nMaxSize)
  263.     {
  264.         // it fits
  265.         if (nNewSize > m_nSize)
  266.         {
  267.             // initialize the new elements
  268. $ifdef HAS_CREATE
  269.             ConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
  270. $else
  271.             memset(&m_pData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(TYPE));
  272. $endif
  273.         }
  274. $ifdef HAS_CREATE
  275.         else if (m_nSize > nNewSize)  // destroy the old elements
  276.             DestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
  277. $endif
  278.         m_nSize = nNewSize;
  279.     }
  280.     else
  281.     {
  282.         // otherwise, grow array
  283.         int nGrowBy = m_nGrowBy;
  284.         if (nGrowBy == 0)
  285.         {
  286.             // heuristically determine growth when nGrowBy == 0
  287.             //  (this avoids heap fragmentation in many situations)
  288.             nGrowBy = min(1024, max(4, m_nSize / 8));
  289.         }
  290.         int nNewMax;
  291.         if (nNewSize < m_nMaxSize + nGrowBy)
  292.             nNewMax = m_nMaxSize + nGrowBy;  // granularity
  293.         else
  294.             nNewMax = nNewSize;  // no slush
  295.  
  296.         ASSERT(nNewMax >= m_nMaxSize);  // no wrap around
  297. #ifdef SIZE_T_MAX
  298.         ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  299. #endif
  300.         TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)];
  301.  
  302.         // copy new data from old
  303.         memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
  304.  
  305.         // construct remaining elements
  306.         ASSERT(nNewSize > m_nSize);
  307. $ifdef HAS_CREATE
  308.         ConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
  309. $else
  310.         memset(&pNewData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(TYPE));
  311. $endif
  312.  
  313.         // get rid of old stuff (note: no destructors called)
  314.         delete[] (BYTE*)m_pData;
  315.         m_pData = pNewData;
  316.         m_nSize = nNewSize;
  317.         m_nMaxSize = nNewMax;
  318.     }
  319. }
  320.  
  321. template<class TYPE, class ARG_TYPE>
  322. int CArray<TYPE, ARG_TYPE>::Append(const CArray& src)
  323. {
  324.     ASSERT_VALID(this);
  325.     ASSERT(this != &src);    // cannot append to itself
  326.  
  327.     int nOldSize = m_nSize;
  328.     SetSize(m_nSize + src.m_nSize);
  329. $ifdef HAS_CREATE
  330.     CopyElements(m_pData + nOldSize, src.m_pData, src.m_nSize);
  331. $else
  332.     memcpy(m_pData + nOldSize, src.m_pData, src.m_nSize * sizeof(TYPE));
  333. $endif
  334.     return nOldSize;
  335. }
  336.  
  337. template<class TYPE, class ARG_TYPE>
  338. void CArray<TYPE, ARG_TYPE>::Copy(const CArray& src)
  339. {
  340.     ASSERT_VALID(this);
  341.     ASSERT(this != &src);    // cannot append to itself
  342.  
  343.     SetSize(src.m_nSize);
  344. $ifdef HAS_CREATE
  345.     CopyElements(m_pData, src.m_pData, src.m_nSize);
  346. $else
  347.     memcpy(m_pData, src.m_pData, src.m_nSize * sizeof(TYPE));
  348. $endif
  349. }
  350.  
  351. template<class TYPE, class ARG_TYPE>
  352. void CArray<TYPE, ARG_TYPE>::FreeExtra()
  353. {
  354.     ASSERT_VALID(this);
  355.  
  356.     if (m_nSize != m_nMaxSize)
  357.     {
  358.         // shrink to desired size
  359. #ifdef SIZE_T_MAX
  360.         ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  361. #endif
  362.         TYPE* pNewData = NULL;
  363.         if (m_nSize != 0)
  364.         {
  365.             pNewData = (TYPE*) new BYTE[m_nSize * sizeof(TYPE)];
  366.             // copy new data from old
  367.             memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
  368.         }
  369.  
  370.         // get rid of old stuff (note: no destructors called)
  371.         delete[] (BYTE*)m_pData;
  372.         m_pData = pNewData;
  373.         m_nMaxSize = m_nSize;
  374.     }
  375. }
  376.  
  377. /////////////////////////////////////////////////////////////////////////////
  378.  
  379. template<class TYPE, class ARG_TYPE>
  380. void CArray<TYPE, ARG_TYPE>::SetAtGrow(int nIndex, ARG_TYPE newElement)
  381. {
  382.     ASSERT_VALID(this);
  383.     ASSERT(nIndex >= 0);
  384.  
  385.     if (nIndex >= m_nSize)
  386.         SetSize(nIndex+1);
  387.     m_pData[nIndex] = newElement;
  388. }
  389.  
  390. template<class TYPE, class ARG_TYPE>
  391. void CArray<TYPE, ARG_TYPE>::InsertAt(int nIndex, ARG_TYPE newElement, int nCount)
  392. {
  393.     ASSERT_VALID(this);
  394.     ASSERT(nIndex >= 0);    // will expand to meet need
  395.     ASSERT(nCount > 0);     // zero or negative size not allowed
  396.  
  397.     if (nIndex >= m_nSize)
  398.     {
  399.         // adding after the end of the array
  400.         SetSize(nIndex + nCount);  // grow so nIndex is valid
  401.     }
  402.     else
  403.     {
  404.         // inserting in the middle of the array
  405.         int nOldSize = m_nSize;
  406.         SetSize(m_nSize + nCount);  // grow it to new size
  407.         // shift old data up to fill gap
  408.         memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  409.             (nOldSize-nIndex) * sizeof(TYPE));
  410.  
  411.         // re-init slots we copied from
  412. $ifdef HAS_CREATE
  413.         ConstructElements(&m_pData[nIndex], nCount);
  414. $else
  415.         memset(&m_pData[nIndex], 0, nCount * sizeof(TYPE));
  416. $endif
  417.     }
  418.  
  419.     // insert new value in the gap
  420.     ASSERT(nIndex + nCount <= m_nSize);
  421.     while (nCount--)
  422.         m_pData[nIndex++] = newElement;
  423. }
  424.  
  425. template<class TYPE, class ARG_TYPE>
  426. void CArray<TYPE, ARG_TYPE>::RemoveAt(int nIndex, int nCount)
  427. {
  428.     ASSERT_VALID(this);
  429.     ASSERT(nIndex >= 0);
  430.     ASSERT(nCount >= 0);
  431.     ASSERT(nIndex + nCount <= m_nSize);
  432.  
  433.     // just remove a range
  434.     int nMoveCount = m_nSize - (nIndex + nCount);
  435. $ifdef HAS_CREATE
  436.     DestructElements(&m_pData[nIndex], nCount);
  437. $endif
  438.     if (nMoveCount)
  439.         memcpy(&m_pData[nIndex], &m_pData[nIndex + nCount],
  440.             nMoveCount * sizeof(TYPE));
  441.     m_nSize -= nCount;
  442. }
  443.  
  444. template<class TYPE, class ARG_TYPE>
  445. void CArray<TYPE, ARG_TYPE>::InsertAt(int nStartIndex, CArray* pNewArray)
  446. {
  447.     ASSERT_VALID(this);
  448.     ASSERT(pNewArray != NULL);
  449.     ASSERT_KINDOF(CArray, pNewArray);
  450.     ASSERT_VALID(pNewArray);
  451.     ASSERT(nStartIndex >= 0);
  452.  
  453.     if (pNewArray->GetSize() > 0)
  454.     {
  455.         InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  456.         for (int i = 0; i < pNewArray->GetSize(); i++)
  457.             SetAt(nStartIndex + i, pNewArray->GetAt(i));
  458.     }
  459. }
  460. $ifdef IS_ARCHIVE_SERIAL
  461.  
  462. /////////////////////////////////////////////////////////////////////////////
  463. // Serialization
  464.  
  465. template<class TYPE, class ARG_TYPE>
  466. void CArray<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  467. {
  468.     ASSERT_VALID(this);
  469.  
  470.     CObject::Serialize(ar);
  471.  
  472.     if (ar.IsStoring())
  473.     {
  474.         ar.WriteCount(m_nSize);
  475.         for (int i = 0; i < m_nSize; i++)
  476.             ar << m_pData[i];
  477.     }
  478.     else
  479.     {
  480.         DWORD nOldSize = ar.ReadCount();
  481.         SetSize(nOldSize);
  482.         for (int i = 0; i < m_nSize; i++)
  483.             ar >> m_pData[i];
  484.     }
  485. }
  486. $endif //IS_ARCHIVE_SERIAL
  487.  
  488. $ifdef IS_RAW_SERIAL
  489.  
  490. /////////////////////////////////////////////////////////////////////////////
  491. // Serialization
  492.  
  493. template<class TYPE, class ARG_TYPE>
  494. void CArray<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  495. {
  496.     ASSERT_VALID(this);
  497.  
  498.     CObject::Serialize(ar);
  499.  
  500.     if (ar.IsStoring())
  501.     {
  502.         ar.WriteCount(m_nSize);
  503.         ar.Write(m_pData, m_nSize * sizeof(TYPE));
  504.     }
  505.     else
  506.     {
  507.         DWORD nOldSize = ar.ReadCount();
  508.         SetSize(nOldSize);
  509.         ar.Read(m_pData, m_nSize * sizeof(TYPE));
  510.     }
  511. }
  512. $endif //IS_RAW_SERIAL
  513.  
  514. $ifdef IS_SWAP_SERIAL
  515.  
  516. /////////////////////////////////////////////////////////////////////////////
  517. // Serialization
  518.  
  519. template<class TYPE, class ARG_TYPE>
  520. void CArray<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  521. {
  522.     ASSERT_VALID(this);
  523.  
  524.     CObject::Serialize(ar);
  525.  
  526.     if (ar.IsStoring())
  527.     {
  528.         ar.WriteCount(m_nSize);
  529. #ifdef _MAC
  530.         if (!ar.IsByteSwapping())
  531. #endif
  532.         ar.Write(m_pData, m_nSize * sizeof(TYPE));
  533. #ifdef _MAC
  534.         else
  535.         {
  536.             // write each item individually so that it will be byte-swapped
  537.             for (int i = 0; i < m_nSize; i++)
  538.                 ar << m_pData[i];
  539.         }
  540. #endif
  541.     }
  542.     else
  543.     {
  544.         DWORD nOldSize = ar.ReadCount();
  545.         SetSize(nOldSize);
  546.         ar.Read(m_pData, m_nSize * sizeof(TYPE));
  547. #ifdef _MAC
  548.         if (ar.IsByteSwapping())
  549.         {
  550.             for (int i = 0; i < m_nSize; i++)
  551.                 _AfxByteSwap(m_pData[i], (BYTE*)&m_pData[i]);
  552.         }
  553. #endif
  554.     }
  555. }
  556. $endif //IS_SWAP_SERIAL
  557.  
  558. /////////////////////////////////////////////////////////////////////////////
  559. // Diagnostics
  560.  
  561. #ifdef _DEBUG
  562. template<class TYPE, class ARG_TYPE>
  563. void CArray<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
  564. {
  565.     CObject::Dump(dc);
  566.  
  567.     dc << "with " << m_nSize << " elements";
  568.     if (dc.GetDepth() > 0)
  569.     {
  570.         for (int i = 0; i < m_nSize; i++)
  571.             dc << "\n\t[" << i << "] = " << m_pData[i];
  572.     }
  573.  
  574.     dc << "\n";
  575. }
  576.  
  577. template<class TYPE, class ARG_TYPE>
  578. void CArray<TYPE, ARG_TYPE>::AssertValid() const
  579. {
  580.     CObject::AssertValid();
  581.  
  582.     if (m_pData == NULL)
  583.     {
  584.         ASSERT(m_nSize == 0);
  585.         ASSERT(m_nMaxSize == 0);
  586.     }
  587.     else
  588.     {
  589.         ASSERT(m_nSize >= 0);
  590.         ASSERT(m_nMaxSize >= 0);
  591.         ASSERT(m_nSize <= m_nMaxSize);
  592.         ASSERT(AfxIsValidAddress(m_pData, m_nMaxSize * sizeof(TYPE)));
  593.     }
  594. }
  595. #endif //_DEBUG
  596.  
  597. #ifdef AFX_INIT_SEG
  598. #pragma code_seg(AFX_INIT_SEG)
  599. #endif
  600.  
  601. $ifdef IS_SERIAL
  602. IMPLEMENT_SERIAL(CArray, CObject, 0)
  603. $else
  604. IMPLEMENT_DYNAMIC(CArray, CObject)
  605. $endif //!IS_SERIAL
  606.  
  607. /////////////////////////////////////////////////////////////////////////////
  608.